package com.self.cartoon.selfcartoon;

import com.gargoylesoftware.htmlunit.*;
import com.gargoylesoftware.htmlunit.html.*;
import com.gargoylesoftware.htmlunit.javascript.SilentJavaScriptErrorListener;
import org.apache.commons.io.IOUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

public class ImageDownloader {

    //https://m.1kkk.com/ch1-1249452/
    //https://www.kanman.com/91961/1007.html
    public static void main(String[] args) throws Exception {
        //长连接APP
        //webApp交互
        try (final WebClient webClient = new WebClient(BrowserVersion.FIREFOX)) {
            webClient.getOptions().setCssEnabled(true);
            webClient.getOptions().setDownloadImages(true);
            //是否使用不安全的SSL
            webClient.getOptions().setUseInsecureSSL(true);
            //启用JS解释器，默认为true
            webClient.getOptions().setJavaScriptEnabled(true);
            //禁用CSS
            webClient.getOptions().setCssEnabled(true);
            //js运行错误时，是否抛出异常
            webClient.getOptions().setThrowExceptionOnScriptError(false);
            //状态码错误时，是否抛出异常
            webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
            webClient.setAjaxController(new NicelyResynchronizingAjaxController());
            webClient.setJavaScriptErrorListener(new SilentJavaScriptErrorListener());
            //等待js时间
            webClient.waitForBackgroundJavaScript(600*1000);
            //设置超时时间
            webClient.getOptions().setTimeout(1000000);
            webClient.addRequestHeader("Accept-Language", "en-US,en;q=0.5");
            webClient.addRequestHeader("Accept-Encoding", "gzip, deflate, br");
            HtmlPage page = webClient.getPage("https://www.kanman.com/91961/1007.html"); // 替换为实际的URL
            // 确保页面加载完成
            webClient.waitForBackgroundJavaScriptStartingBefore(15 * 1000); // 等待60秒，确保所有JavaScript执行完成

            //缓存img
            Map<String,HtmlImage> cacheImg = new HashMap();

            List<HtmlImage> newImages = findNewImages(page);
            addImg(cacheImg,newImages);

            int scrollDistance = 1000; // 滚动距离，根据需要调整
            int imagesCollectedPerScroll = newImages.size();

            // 模拟滚动并收集新图片
            for (int i = 0; i < 5; i++) {
                System.out.printf("Scroll %d: Collected %d new images.%n", i + 1, imagesCollectedPerScroll);
                simulateScroll(page, scrollDistance); // 执行滚动操作
                webClient.waitForBackgroundJavaScriptStartingBefore(3000); // 等待一段时间以便新内容加载

                newImages = findNewImages(page);
                imagesCollectedPerScroll = newImages.size();
                addImg(cacheImg,newImages);

                // 如果这次滚动没有收集到新图片，可能已到达底部，可以提前结束
                if (imagesCollectedPerScroll == 0) {
                    System.out.println("No new images found during this scroll, assuming end of content.");
                    //跳转至下一章
                    break;
                }
            }

            // 保存所有收集到的图片
            for (HtmlImage image : cacheImg.values()) {
                saveImage(image);
            }
        }
    }

    private static void addImg(Map<String, HtmlImage> cacheImg, List<HtmlImage> newImages) {
        newImages.forEach(item -> {
            String src = item.getSrcAttribute();
            if(cacheImg.containsKey(src)){
                System.out.println("图片重复");
                return;
            }
            cacheImg.put(src, item);
        });
    }

    public static void simulateScroll(HtmlPage page, int scrollDistance) throws IOException {
        // 模拟向下滚动页面
        String script = String.format("window.scrollBy(0, %d);", scrollDistance);
        page.executeJavaScript(script);

        // 等待一段时间让新的内容加载，这里可以根据实际情况调整等待时间
        try {
            Thread.sleep(2000); // 等待2秒，根据实际页面加载速度调整
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("Interrupted while waiting for content to load", e);
        }

        // 可以检查是否还有更多内容需要加载，例如检查某个加载指示器是否消失
        // 然后决定是否继续滚动
    }
    private static List<HtmlImage> findNewImages(HtmlPage page) {
        List<HtmlImage> allImages = new ArrayList<>();
        List<DomElement> elements = page.getByXPath("//div[contains(@class, 'acgn-reader-chapter__swiper-box')]");
        for (DomElement node : elements) {
            if (node instanceof HtmlImage) {
                allImages.add((HtmlImage) node);
            }
            for (HtmlElement htmlElement : node.getElementsByTagName("img")) {
                allImages.add((HtmlImage) htmlElement);
            }
        }
        return allImages;
    }

    private static void saveImage(HtmlImage image) throws IOException {
        //String src = image.getAttribute("data-original");
        String src = image.getSrcAttribute();

        // 检查是否为Base64编码的图像
        if (src.startsWith("data:image/")) {
            saveBase64EncodedImage(src);
        } else {
            WebResponse response = image.getWebResponse(true); // 确保图片数据被下载
            if(response == null){
                System.out.println("error log src = "+ src);
                return;
            }
            if (response.getStatusCode() == 200) {
                String fileName = extractFileNameFromUrl(src);
                try (InputStream inputStream = response.getContentAsStream()
                    // FileOutputStream fileOutputStream = new FileOutputStream("D:/images/t1/image_" + fileName)
                ) {
                    // 将InputStream转换为Base64字符串
                    byte[] imageBytes = IOUtils.toByteArray(inputStream);
                    String base64Image = Base64.getEncoder().encodeToString(imageBytes);
                    System.out.println("data:image/jpg;base64," + base64Image);
//                    byte[] buffer = new byte[1024];
//                    int bytesRead;
//                    while ((bytesRead = inputStream.read(buffer)) != -1) {
//                        fileOutputStream.write(buffer, 0, bytesRead);
//                    }
                }

                System.out.println("Image saved: image_" + fileName);
            } else {
                System.err.println("Failed to load image - Status code: " + response.getStatusCode());
            }
        }
    }

    private static void saveBase64EncodedImage(String base64Data) throws IOException {
        // 移除"data:image/<type>;base64,"部分
        String base64Image = base64Data.substring(base64Data.indexOf(",") + 1);

        byte[] imageBytes = Base64.getDecoder().decode(base64Image);
        // 生成文件名，这里简单使用"base64_image.jpg"作为示例，你可以根据需要生成更具体的文件名
        String fileName = UUID.randomUUID().toString() + ".jpg";

        try (FileOutputStream fos = new FileOutputStream("D:/images/t1/image_" + fileName)) {
            fos.write(imageBytes);
        }

        System.out.println("Base64 encoded image saved: image_" + fileName);
    }

    private static String extractFileNameFromUrl(String url) {
        int i = url.lastIndexOf("/");
        int j = url.indexOf("?");
        return url.substring(i + 1, j != -1 ? j : url.length());
    }
}
